/***********************************************
 **** 版权声明处 **
 ****  为了方便阅读和维护，请严格遵守相关代码规范，谢谢   ****
 *******************************************/
package bpm.graphic
{
	import flash.events.Event;
	import flash.geom.Point;
	
	import mx.core.UIComponent;
	import mx.events.MoveEvent;
	
	import spark.primitives.Path;
	
	import utils.Geometry;

	/*******************************************
	 **** huangjixin, 2012-10-26, 下午4:34:51 **
	 **** 请一句话表述该类主要作用  **
	 *******************************************/
	public class Link extends Render
	{
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// private 类私有静态变量和静态常量声明处。（全部大写，使用下划线进行分割）
		// 例如：private static const EXAMPLE:String = "example";
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// public 类公有静态变量和静态常量声明处。（全部大写，使用下划线进行分割）
		// 例如：public static const EXAMPLE:String = "example";
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// private 私有变量声明处，请以“_”开头定义变量
		// 例如：private var _example:String;
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		private var _shapeType:String = LinkShapeType.ORTHOGONAL;
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// public 公有变量声明处
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		[SkinPart(required="true")]
		public var path:Path;
		[SkinPart(required="true")]
		public var endArrow:Path;
		/**
		 * 起始节点。 
		 */
		public var startNode:Node;
		/**
		 * 结束节点。 
		 */
		public var endNode:Node;
		
		private var _startPort:Port;
		
		private var _endPort:Port;
		
		private var _fallbackStartPoint:Point = new Point();
		private var _fallbackEndPoint:Point = new Point();
		
		[Bindable]
		public var data:String = "M 0 0 L 0 0";
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 构造函数，初始化相关工作可以放在里面
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		public function Link()
		{
			super();
		}//构造函数结束
		
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// getter和setter函数
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 相关事件响应函数和逻辑函数存放处
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

		
		[Inspectable(enumeration="straight,orthogonal",defaultValue="straight")]
		public function get shapeType():String
		{
			return _shapeType;
		}

		public function set shapeType(value:String):void
		{
			_shapeType = value;
			invalidateDisplayList();
		}

		[Bindable(event="endPortChange")]
		public function get endPort():Port
		{
			return _endPort;
		}

		public function set endPort(value:Port):void
		{
			if( _endPort !== value)
			{
				if(value){
					_endPort = value;
					_endPort.addEventListener(Event.ENTER_FRAME,onEnterFrame);
				}else{
					if(_endPort){
						if(_endPort.hasEventListener(Event.ENTER_FRAME)){
							_endPort.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
						}
					}
					_endPort = value;
				}
				_endPort = value;
				dispatchEvent(new Event("endPortChange"));
			}
		}

		[Bindable(event="startPortChange")]
		public function get startPort():Port
		{
			return _startPort;
		}

		public function set startPort(value:Port):void
		{
			if( _startPort !== value)
			{
				if(value){
					_startPort = value;
					_startPort.addEventListener(Event.ENTER_FRAME,onEnterFrame);
					_startPort.addEventListener(MoveEvent.MOVE,onMove);
				}else{
					if(_startPort){
						if(_startPort.hasEventListener(Event.ENTER_FRAME)){
							_startPort.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
						}
					}
					_startPort = value;
				}
				
				dispatchEvent(new Event("startPortChange"));
			}
		}
		
		protected function onMove(event:MoveEvent):void
		{
			trace("ok");
		}
		
		[Bindable(event="fallbackEndPointChange")]
		public function get fallbackEndPoint():Point
		{
			return _fallbackEndPoint;
		}

		public function set fallbackEndPoint(value:Point):void
		{
			if( _fallbackEndPoint !== value)
			{
				_fallbackEndPoint = value;
				dispatchEvent(new Event("fallbackEndPointChange"));
				invalidateDisplayList();
			}
		}

		[Bindable(event="fallbackStartPointChange")]
		/**
		 * 回调开始节点。 
		 */
		public function get fallbackStartPoint():Point
		{
			return _fallbackStartPoint;
		}

		/**
		 * @private
		 */
		public function set fallbackStartPoint(value:Point):void
		{
			if( _fallbackStartPoint !== value)
			{
				_fallbackStartPoint = value;
				dispatchEvent(new Event("fallbackStartPointChange"));
				invalidateDisplayList();
			}
		}

		/**
		 *  
		 * @param event
		 * 
		 */
		protected function onEnterFrame(event:Event):void
		{
			if(startPort){
				fallbackStartPoint.x = startPort.ownerObject.x+startPort.ownerObject.width/2;
				fallbackStartPoint.y = startPort.ownerObject.y+startPort.ownerObject.height/2;
				
				if(startPort.id == "BOTTOM"){
					fallbackStartPoint.x = startPort.x + startPort.width/2;
					fallbackStartPoint.y = startPort.y + startPort.height/2;
				}
				if(startPort.id == "TOP"){
					fallbackStartPoint.x = startPort.x + startPort.width/2;
					fallbackStartPoint.y = startPort.y - startPort.height/2;
				}
				if(startPort.ownerObject.parent){
					fallbackStartPoint = startPort.ownerObject.parent.localToGlobal(fallbackStartPoint);
					fallbackStartPoint = this.globalToLocal(fallbackStartPoint);
				}
				
				
			}
			if(endPort){
				fallbackEndPoint.x = endPort.ownerObject.x+endPort.ownerObject.width/2;
				fallbackEndPoint.y = endPort.ownerObject.y+endPort.ownerObject.height/2;
				if(endPort.id == "BOTTOM"){
					fallbackEndPoint.x = endPort.x+ endPort.width/2;
					fallbackEndPoint.y = endPort.y+ endPort.height/2;
				}
				if(endPort.id == "TOP"){
					fallbackEndPoint.x = endPort.x+ endPort.width/2;
					fallbackEndPoint.y = endPort.y- endPort.height/2;
				}
				
				if(endPort.ownerObject.parent){
					fallbackEndPoint = endPort.ownerObject.parent.localToGlobal(fallbackEndPoint);
					fallbackEndPoint = this.globalToLocal(fallbackEndPoint);
				}
			}
			
			if (shapeType == LinkShapeType.ORTHOGONAL){
				computeOrthogonalLine()
			}else if (shapeType == LinkShapeType.STRAIGHT){
				computeStraightLine();
			}
			
			if(path){
				path.data = data;			
			}
		}
		
		public function lineFun(point1:Point,point2:Point,x:Number):Number{
			if(point1.x == point2.x && point1.y == point2.y){
				return 0;
			}
			var result:Number = 1 * ((point2.y - point1.y) * (x - point1.x) / (point2.x - point1.x) + point1.y);
			return result;
		}
		
		private function computeStraightLine():void
		{
			data = "M "+fallbackStartPoint.x +"," + fallbackStartPoint.y + "L "+fallbackEndPoint.x+","+fallbackEndPoint.y;
		}//computeLine结束
		
		private function computeOrthogonalLine():void
		{
			data = "M "+fallbackStartPoint.x +"," + fallbackStartPoint.y + "L "+(fallbackStartPoint.x/2+fallbackEndPoint.x/2)
				+","+fallbackStartPoint.y + " "+ (fallbackStartPoint.x/2+fallbackEndPoint.x/2) + ","+fallbackEndPoint.y+ " "
				+fallbackEndPoint.x+","+fallbackEndPoint.y;
			if(Math.abs(fallbackEndPoint.x-fallbackStartPoint.x)<Math.abs(fallbackEndPoint.y-fallbackStartPoint.y)){
				data = "M "+fallbackStartPoint.x +"," + fallbackStartPoint.y + "L "+fallbackStartPoint.x
					+","+ (fallbackStartPoint.y/2+fallbackEndPoint.y/2) + " "+ fallbackEndPoint.x + ","+(fallbackStartPoint.y/2+fallbackEndPoint.y/2)+ " "
					+fallbackEndPoint.x+","+fallbackEndPoint.y;
			}
		}//computeLine结束
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// override 覆盖函数
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		override public function clone():Node{
			var cloneNode:Node = super.clone();
			if(cloneNode is Link){
				Link(cloneNode).fallbackStartPoint = this.fallbackStartPoint;
				Link(cloneNode).fallbackEndPoint = this.fallbackEndPoint;
				Link(cloneNode).startNode = this.startNode;
				Link(cloneNode).endNode = this.endNode;
				Link(cloneNode).shapeType = this.shapeType;
			}
			
			return cloneNode;
		} 
		
		override protected function partAdded(partName:String, instance:Object):void{
			/*if(instance == path){
				if (shapeType == LinkShapeType.ORTHOGONAL){
					computeOrthogonalLine()
				}else if (shapeType == LinkShapeType.STRAIGHT){
					computeStraightLine();
				}
				path.data = data;	
			}	
			
			if(instance == endArrow){
				if(fallbackEndPoint.x >= fallbackStartPoint.x){
					endArrow.x = fallbackEndPoint.x+endArrow.width/2;
					endArrow.rotation = 0;
				}else{
					endArrow.x = fallbackEndPoint.x - endArrow.width/2;
					endArrow.rotation = 180;
				}
				endArrow.y = fallbackEndPoint.y;
			}*/
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth,unscaledHeight);
			/*var point:Point = new Point();
			point.x = Math.min(fallbackStartPoint.x,fallbackEndPoint.x);
			point.y = Math.min(fallbackStartPoint.y,fallbackEndPoint.y);
			point = localToGlobal(point);
			point = this.parent.globalToLocal(point);
			trace(x+", "+y);
			x = point.x;
			y = point.y;*/
			/*width = Math.abs(fallbackEndPoint.x-fallbackStartPoint.x);
			height = Math.abs(fallbackEndPoint.y-fallbackStartPoint.y);*/
			if (shapeType == LinkShapeType.ORTHOGONAL){
				computeOrthogonalLine()
			}else if (shapeType == LinkShapeType.STRAIGHT){
				computeStraightLine();
			}
			
			path.data = data;
			
			if(fallbackEndPoint.x >= fallbackStartPoint.x){
				endArrow.x = fallbackEndPoint.x+endArrow.width/2;
				endArrow.rotation = 0;
			}else{
				endArrow.x = fallbackEndPoint.x - endArrow.width/2;
				endArrow.rotation = 180;
			}
			endArrow.y = fallbackEndPoint.y;
			
			var edgeAngle:Number;
			var mArrowBase:Point;
			
			edgeAngle = Math.atan2(fallbackEndPoint.y - fallbackStartPoint.y,fallbackEndPoint.x - fallbackStartPoint.x);
			endArrow.rotation = Geometry.rad2deg(edgeAngle);
			
			mArrowBase = Point.polar(Point.distance(fallbackEndPoint,fallbackStartPoint) + endArrow.width,edgeAngle);
			mArrowBase.offset(fallbackStartPoint.x,fallbackStartPoint.y);
			endArrow.x = mArrowBase.x;
			endArrow.y = mArrowBase.y;
			
			
		}
	}//类结束
}//包结束